package com.hanserwei.han_picture.manager;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.hanserwei.han_picture.config.TencentCosClient;
import com.hanserwei.han_picture.domain.exception.ApiException;
import com.hanserwei.han_picture.domain.file.UploadPictureResult;
import com.hanserwei.han_picture.enums.ResponseCodeEnum;
import com.hanserwei.han_picture.utils.ThrowUtils;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.ciModel.persistence.ImageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.Date;
import java.util.Set;

/**
 * 业务相关文件上传类
 *
 * @author hanserwei
 */
@Service
@RequiredArgsConstructor
@Slf4j
@Deprecated
public class FileManager {

    // 允许的图片MIME类型
    private static final Set<String> ALLOWED_CONTENT_TYPES = Set.of(
            "image/jpeg",
            "image/png",
            "image/webp",
            "image/jpg"
    );
    // 允许的最大文件大小 (3MB)
    private static final long MAX_FILE_SIZE_BYTES = 8 * 1024 * 1024;
    /**
     * 通用的文件上传与下载
     */
    private final CosManager cosManager;
    /**
     * 腾讯云COS
     */
    private final TencentCosClient tencentCosClient;

    /**
     * 删除临时文件
     *
     * @param file 临时文件
     */

    private static void deleteTempFile(File file) {
        if (file != null) {
            boolean deleted = file.delete();
            if (!deleted) {
                log.error("删除临时文件失败");
            }
        }
    }

    /**
     * 文件上传
     *
     * @param multipartFile    本地文件
     * @param uploadPathPrefix 上传路径前缀
     * @return 封装图片基本信息的对象
     */
    public UploadPictureResult uploadPicture(MultipartFile multipartFile, String uploadPathPrefix) {
        // 1.校验图片
        validPicture(multipartFile);
        // 2.拼接图片名称
        String date = DateUtil.formatDate(new Date());
        String uuid = RandomUtil.randomString(10);
        String suffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
        String fileName = String.format("%s_%s.%s", date, uuid, suffix);
        // 3.划分文件夹
        String uploadPath = String.format("/%s/%s", uploadPathPrefix, fileName);
        // 4.上传文件到cos
        File file = null;
        // 5.删除临时文件
        try {
            // 创建临时文件
            file = File.createTempFile(fileName, null);
            // 将multipartFile写入临时文件
            multipartFile.transferTo(file);
            // 上传文件到COS
            PutObjectResult putObjectResult = cosManager.putPictureObject(uploadPath, file);
            // 数据万象处理图片
            ImageInfo imageInfo = putObjectResult.getCiUploadResult().getOriginalInfo().getImageInfo();
            int width = imageInfo.getWidth();
            int height = imageInfo.getHeight();
            // 计算图片宽高比
            double picScale = NumberUtil.round((double) width / height, 2).doubleValue();
            // 封装图片信息
            UploadPictureResult result = new UploadPictureResult();
            result.setUrl(tencentCosClient.getHost() + uploadPath);
            result.setPicName(FileUtil.mainName(multipartFile.getOriginalFilename()));
            result.setPicSize(FileUtil.size(file));
            result.setPicWidth(width);
            result.setPicHeight(height);
            result.setPicScale(picScale);
            result.setPicFormat(imageInfo.getFormat());
            return result;
        } catch (Exception e) {
            log.error("上传文件失败！", e);
            throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "上传文件失败！");
        } finally {
            deleteTempFile(file);
        }
    }

    public UploadPictureResult uploadPictureByUrl(String fileUrl, String uploadPathPrefix) {
        validPictureUrl(fileUrl);
        // 2.拼接文件名称
        String date = DateUtil.formatDate(new Date());
        String uuid = RandomUtil.randomString(10);
        String mainName = FileUtil.mainName(fileUrl);
        String fileName = String.format("%s_%s.%s", date, uuid, mainName);
        // 3.划分文件夹
        String uploadPath = String.format("/%s/%s", uploadPathPrefix, fileName);
        // 4.上传文件到cos
        File file = null;
        try {
            // 创建临时文件
            String tempPrefix = "upload_" + RandomUtil.randomString(2);
            file = File.createTempFile(tempPrefix, null);
            // 下载文件
            HttpUtil.downloadFile(fileUrl, file);
            // 上传文件到cos
            PutObjectResult putObjectResult = cosManager.putPictureObject(uploadPath, file);
            // 数据万象处理图片
            ImageInfo imageInfo = putObjectResult.getCiUploadResult().getOriginalInfo().getImageInfo();
            int width = imageInfo.getWidth();
            int height = imageInfo.getHeight();
            // 计算图片宽高比
            double picScale = NumberUtil.round((double) width / height, 2).doubleValue();
            // 封装图片信息
            UploadPictureResult result = new UploadPictureResult();
            result.setUrl(tencentCosClient.getHost() + uploadPath);
            result.setPicName(mainName);
            result.setPicSize(FileUtil.size(file));
            result.setPicWidth(width);
            result.setPicHeight(height);
            result.setPicScale(picScale);
            result.setPicFormat(imageInfo.getFormat());
            return result;
        } catch (Exception e) {
            log.error("创建临时文件失败！", e);
            throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "上传文件失败！");
        } finally {
            deleteTempFile(file);
        }
    }

    private void validPictureUrl(String fileUrl) {
        ThrowUtils.throwIf(StrUtil.isBlank(fileUrl), ResponseCodeEnum.INVALID_PARAMETER, "文件地址不能为空！");

        URL url;
        // 1. 校验文件地址格式
        try {
            URI uri = new URI(fileUrl);
            url = uri.toURL();
        } catch (Exception e) {
            throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件地址格式错误！");
        }

        // 2. 验证URL协议
        String protocol = url.getProtocol();
        if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
            throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件地址协议错误！");
        }

        // 3. 验证URL是否存在、类型和大小 (HEAD 请求)
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("HEAD");
            connection.setConnectTimeout(5000); // 5秒连接超时
            connection.setReadTimeout(5000);    // 5秒读取超时

            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件不存在或无法访问！");
            }

            // 校验文件类型 (Content-Type)
            String contentType = connection.getContentType();
            if (StrUtil.isBlank(contentType) || !ALLOWED_CONTENT_TYPES.contains(contentType.toLowerCase())) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件类型不支持！");
            }

            // 校验文件大小 (Content-Length)
            long contentLength = connection.getContentLengthLong();
            if (contentLength > MAX_FILE_SIZE_BYTES) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件大小不能超过3MB！");
            }

        } catch (Exception e) {
            log.error("验证文件地址失败！URL: {}", fileUrl, e);
            throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "验证文件地址失败！");
        } finally {
            // 确保资源被释放
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    /**
     * 校验图片
     *
     * @param multipartFile 图片文件
     */
    private void validPicture(MultipartFile multipartFile) {
        ThrowUtils.throwIf(ObjUtil.isNull(multipartFile), ResponseCodeEnum.INVALID_PARAMETER, "文件不存在！");
        // 1.校验文件大小
        long fileSize = multipartFile.getSize();
        // 2.设置文件大小限制
        final long MAX_FILE_SIZE = 1024 * 1024 * 10;
        ThrowUtils.throwIf(fileSize > MAX_FILE_SIZE, ResponseCodeEnum.INVALID_PARAMETER, "文件大小超出限制！");
        // 3.校验文件类型
        String originalFilename = multipartFile.getOriginalFilename();
        String fileSuffix = FileUtil.getSuffix(originalFilename);
        // 4.设置文件类型限制
        final Set<String> ALLOWED_FILE_SUFFIX = Set.of("png", "jpg", "jpeg", "webp");
        ThrowUtils.throwIf(fileSuffix != null && !ALLOWED_FILE_SUFFIX.contains(fileSuffix), ResponseCodeEnum.INVALID_PARAMETER, "文件类型不支持！");
    }
}
